/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.txweb.util;

import com.jspx.boot.EnvFactory;
import com.jspx.boot.environment.EnvironmentTemplate;
import com.jspx.boot.sign.ErrorRocCode;
import com.jspx.boot.sign.HttpStatusType;
import com.jspx.boot.sign.SafetyLevel;
import com.jspx.json.JSONException;
import com.jspx.json.XML;
import com.jspx.scriptmark.ScriptMark;
import com.jspx.scriptmark.ScriptmarkEnv;
import com.jspx.scriptmark.config.TemplateConfigurable;
import com.jspx.scriptmark.core.ScriptMarkEngine;
import com.jspx.scriptmark.load.AbstractSource;
import com.jspx.scriptmark.load.FileSource;
import com.jspx.txweb.ActionProxy;
import com.jspx.txweb.dispatcher.Dispatcher;
import com.jspx.txweb.table.Role;
import org.slf4j.Logger;
import com.jspx.boot.environment.Environment;
import org.slf4j.LoggerFactory;
import com.jspx.json.JSONArray;
import com.jspx.json.JSONObject;
import com.jspx.security.utils.EncryptUtil;
import com.jspx.sioc.BeanFactory;
import com.jspx.sioc.Sioc;
import com.jspx.txweb.Action;
import com.jspx.txweb.annotation.*;
import com.jspx.txweb.env.TXWeb;
import com.jspx.txweb.support.ActionSupport;
import com.jspx.txweb.support.MultipartSupport;
import com.jspx.txweb.support.ValidatorAction;
import com.jspx.txweb.turnpage.TurnPageButton;
import com.jspx.txweb.turnpage.impl.TurnPageButtonImpl;
import com.jspx.upload.MultipartRequest;
import com.jspx.upload.multipart.CoveringsFileRenamePolicy;
import com.jspx.upload.multipart.FileRenamePolicy;
import com.jspx.upload.multipart.JspxNetFileRenamePolicy;
import com.jspx.utils.*;
import com.jspx.txweb.validator.Validator;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.util.*;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User:chenYuan (mail:39793751@qq.com)
 * Date: 2006-12-27
 * Time: 15:16:56
 * LifecycleManager
 */
public class TXWebUtil {

    private static final Logger log = LoggerFactory.getLogger(TXWebUtil.class);
    final static private EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
    final static private boolean debug = envTemplate.getBoolean(Environment.logJspxDebug);

    public final static String chainType = "chain";
    public final static String redirectType = "redirect";
    public final static String xmlType = "xml";
    public final static String jsonType = "json";
    public final static String javascriptType = "javascript";
    public final static String htmlType = "html";
    private static BeanFactory beanFactory = EnvFactory.getBeanFactory();
    public final static String defaultExecute = "execute";
    public final static String defMethod = "method";
    public final static String AT = "@";
    //安全跳过,这些方法不接受请求发送的参数
    private final static String[] actionSafeMethod = new String[]{"setActionLogTitle", "setActionLogContent", "setActionResult", "setProcess", "isRepeatPost"};

    private TXWebUtil() {

    }

    //包含特殊字符的符号,安全过滤掉的符号 / 表示路径会用
    private final static char[] incertitudeChars = {
            '\\', '$', '\'', '#', '!', '\"', '<', '>'
    };

    //保留空格的目的是确保不会和调用方法名称重复，重复就不会调用执行
    private final static String[] safetyFilterKeys = {
            "<script>", " or ", " and ", "update ", " where ", "select ", " from ", "delete ", "insert ", "drop ", "xp_cmdshell", "wscript.shell", "create ", "shell "
    };

    // 危险的javascript:关键字j av a script
    private final static Pattern[] DANGEROUS_TOKENS = new Pattern[]{Pattern.compile("^j\\s*a\\s*v\\s*a\\s*s\\s*c\\s*r\\s*i\\s*p\\s*t\\s*:",
            Pattern.CASE_INSENSITIVE)};

    // javascript:替换字符串（全角中文字符）
    private final static String[] DANGEROUS_TOKEN_REPLACEMENTS = new String[]{"ＪＡＶＡＳＣＲＩＰＴ："};


    /**
     * 因为外部有可配置的安全过滤,这里就弱化,只判断基本部分
     *
     * @param str       参数
     * @param maxLength 允许最大长度
     * @param level     安全级别
     * @return 1:基本到安全，判断是否有特殊符号 IncertitudeChars
     * 2:sql，判断是否有sql符号 sqlKeys
     * 3:url 安全过滤 safetyUrlKeys
     */
    public static boolean isSafe(String str, int maxLength, int level) {
        if (str == null) return true;
        if (str.length() > maxLength) return false;

        //1
        for (char c : incertitudeChars) {
            if (str.indexOf(c) != -1) return false;
        }
        if (level == SafetyLevel.Low) return true;

        //2
        str = str.toLowerCase();
        for (String safetyUrlKey : safetyFilterKeys) {
            if (str.contains(safetyUrlKey)) {
                return false;
            }
        }
        if (level < SafetyLevel.Middle) return true;
        for (String safetyUrlKey : StringUtil.split(HtmlUtil.safeFilter_delAllTags, StringUtil.COMMAS)) {
            if (str.contains(safetyUrlKey)) {
                return false;
            }
        }
        return true;
    }


    public static String getSafeFilter(String str, int maxLength, int level) {
        if (str == null) return StringUtil.empty;
        if (str.length() > maxLength) return StringUtil.empty;
        String result = HtmlUtil.deleteHtml(str);
        //1
        for (char c : incertitudeChars) {
            result = StringUtil.replaceIgnoreCase(result, c + "", StringUtil.empty);
        }
        if (level < 1) return result;
        //2
        for (int i = 0; i < DANGEROUS_TOKENS.length; ++i) {
            str = DANGEROUS_TOKENS[i].matcher(str).replaceAll(
                    DANGEROUS_TOKEN_REPLACEMENTS[i]);
        }
        for (String safetyUrlKey : safetyFilterKeys) {
            result = StringUtil.replaceIgnoreCase(result, safetyUrlKey, StringUtil.halfToFull(safetyUrlKey));
        }
        if (level < 2) return result;
        //3
        try {
            result = HtmlUtil.getSafeFilter(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 自动生成Querystring参数
     *
     * @param request 请求
     * @param paras   参数
     * @return 请求字符串
     * @throws java.io.UnsupportedEncodingException 不支持的编码
     */
    private static String getQueryString(HttpServletRequest request, String paras, int level) throws Exception {
        if (request == null) return StringUtil.empty;
        StringBuilder queryString = new StringBuilder();
        ///////////////载入所有参数 begin
        if (paras != null && paras.equals("*")) {
            String[] names = RequestUtil.getParameterNames(request);
            int i = 0;
            if (names != null) {
                for (String key : names) {
                    String value = request.getParameter(key);
                    boolean isSafe = isSafe(value, 200, level);
                    if (value != null && isSafe) {
                        if (i != 0) {
                            queryString.append("&");
                        }
                        queryString.append(key).append("=").append(java.net.URLEncoder.encode(getSafeFilter(value, 200, level), request.getCharacterEncoding()));
                        i++;
                    }
                }
            }
            return queryString.toString();
        }
        ///////////////载入所有参数 end
        String[] paraArray = StringUtil.split(paras, StringUtil.SEMICOLON);
        String[] names = RequestUtil.getParameterNames(request);
        int i = 0;
        if (names != null) {
            for (String key : names) {
                if (ArrayUtil.inArray(paraArray, key, true)) {
                    String value = request.getParameter(key);
                    boolean isSafe = isSafe(value, 200, level);
                    if (value != null & isSafe) {
                        if (i != 0) {
                            queryString.append("&");
                        }
                        queryString.append(key).append("=").append(java.net.URLEncoder.encode(getSafeFilter(value, 200, level), request.getCharacterEncoding()));
                        i++;
                    }
                }
            }
        }
        return queryString.toString();
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * 上传命名方式
     *
     * @param covering 是否覆盖
     * @return cos 上传的命名方式
     */
    public static FileRenamePolicy getFileRenamePolicy(final String covering) {
        if ("CoveringsFileRenamePolicy".equalsIgnoreCase(covering)) {
            return new CoveringsFileRenamePolicy();
        } else if ("DateRandomNamePolicy".equalsIgnoreCase(covering)) {
            return new CoveringsFileRenamePolicy();
        } else if ("DefaultFileRenamePolicy".equalsIgnoreCase(covering)) {
            return new CoveringsFileRenamePolicy();
        } else {
            return new JspxNetFileRenamePolicy();
        }
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * 上传请求
     *
     * @param action 设置上传方式的请求
     * @throws Exception 错误
     */
    public static void setMulRequest(final ActionSupport action) throws Exception {
        if (!RequestUtil.isMultipart(action.getRequest())) return;
        Method[] methods = ClassUtil.getDeclaredMethods(action.getClass());//字段
        for (Method method : methods) {
            MulRequest mulRequest = method.getAnnotation(MulRequest.class);
            if (mulRequest != null) {
                String saveDirectory = mulRequest.saveDirectory();
                if (saveDirectory.startsWith(AT)) {
                    saveDirectory = saveDirectory.substring(1, saveDirectory.length());
                    saveDirectory = (String) BeanUtil.getProperty(action, saveDirectory);
                }

                String fileType = mulRequest.fileTypes();
                if (fileType.startsWith(AT)) {
                    fileType = fileType.substring(1, fileType.length());
                    fileType = (String) BeanUtil.getProperty(action, fileType);
                }

                String covering = mulRequest.covering();
                if (covering.startsWith(AT)) {
                    covering = covering.substring(1, covering.length());
                    covering = BeanUtil.getProperty(action, covering).toString();
                }


                String maxPostSize = mulRequest.maxPostSize();
                if (maxPostSize.startsWith(AT)) {
                    maxPostSize = maxPostSize.substring(1, maxPostSize.length());
                    maxPostSize = BeanUtil.getProperty(action, maxPostSize).toString();
                }
                int iMaxPostSize = StringUtil.toInt(maxPostSize);

                String[] fileTypes = null;
                if (!StringUtil.isNULL(fileType) && !fileType.equals("*"))
                    fileTypes = StringUtil.split(StringUtil.replace(fileType, StringUtil.COMMAS, StringUtil.SEMICOLON), StringUtil.SEMICOLON);
                final MultipartRequest multipartRequest = new MultipartRequest(action.getRequest(), saveDirectory, iMaxPostSize, getFileRenamePolicy(covering), fileTypes);
                BeanUtil.setSimpleProperty(action, method.getName(), multipartRequest);
                action.setRequest(multipartRequest);
            }
        }
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * 推荐更多的使用ajax方式分页
     *
     * @param action action
     * @throws Exception 异常
     */
    public static void setTurnPage(final Action action) throws Exception {

        HttpServletRequest request = action.getRequest();
        if (request == null) return;
        Method[] methods = ClassUtil.getDeclaredMethods(action.getClass());//字段
        for (Method method : methods) {
            TurnPage turnPage = method.getAnnotation(TurnPage.class);
            if (turnPage != null) {
                String enable = action.getEnv(ActionSupport.Key_PageEnable);
                if (StringUtil.toBoolean(enable)) {
                    enable = "true";
                } else {
                    enable = turnPage.enable();
                    if (enable.startsWith(AT)) {
                        enable = enable.substring(1, enable.length());
                        enable = ObjectUtil.toString(BeanUtil.getProperty(action, enable));
                    } else if (enable.startsWith("[") && enable.endsWith("]")) {
                        enable = StringUtil.substringBetween(enable, "[", "]");
                        String urlName = action.getEnv(ActionSupport.Key_ActionName);
                        assert enable != null;
                        enable = BooleanUtil.toString(urlName.matches(enable));
                    }
                }
                if (!StringUtil.toBoolean(enable)) continue;
                TurnPageButton turnPageButton = new TurnPageButtonImpl();
                String currentPage = turnPage.currentPage();
                int iCurrentPage = 0;
                if (currentPage.startsWith(AT)) {
                    currentPage = currentPage.substring(1, currentPage.length());
                    iCurrentPage = ObjectUtil.toInt(BeanUtil.getProperty(action, currentPage));
                } else if (StringUtil.isNumber(currentPage)) {
                    iCurrentPage = StringUtil.toInt(currentPage);
                }
                turnPageButton.setCurrentPage(iCurrentPage);
                //参数方式载入 默认行数 begin
                String rows = turnPage.rows();
                int iRow = 0;
                if (rows.startsWith(AT)) {
                    rows = rows.substring(1, rows.length());
                    iRow = ObjectUtil.toInt(BeanUtil.getProperty(action, rows));
                } else if (StringUtil.isNumber(rows)) {
                    iRow = StringUtil.toInt(rows);
                }

                turnPageButton.setCount(iRow);
                //参数方式载入 默认行数 end

                /////////设置参数 begin
                String sParas = turnPage.params();
                if (StringUtil.hasLength(sParas) && sParas.startsWith(AT)) {
                    sParas = sParas.substring(1, sParas.length());
                    sParas = (String) BeanUtil.getProperty(action, sParas);
                }
                turnPageButton.setQuerystring(getQueryString(request, sParas, 2));
                /////////设置参数 end

                ////得到行总数 begin
                int iTotalCount;
                String sTotalCount = turnPage.totalCount();
                if (StringUtil.hasLength(sTotalCount) && sTotalCount.startsWith(AT)) {
                    sTotalCount = sTotalCount.substring(1, sTotalCount.length());
                    iTotalCount = ObjectUtil.toInt(BeanUtil.getProperty(action, sTotalCount));
                } else {
                    iTotalCount = StringUtil.toInt(sTotalCount);
                }
                turnPageButton.setTotalCount(iTotalCount);
                ////得到行总数 end

                ////得到模版文件 begin
                String turnFile = turnPage.file();
                if (StringUtil.hasLength(turnFile) && turnFile.startsWith(AT)) {
                    turnFile = turnFile.substring(1, turnFile.length());
                    turnFile = (String) BeanUtil.getProperty(action, turnFile);
                }
                ////得到行总数 end

                ////得到模版文件 begin
                String bound = turnPage.bound();
                if (StringUtil.hasLength(bound) && bound.startsWith(AT)) {
                    bound = bound.substring(1, bound.length());
                    bound = (String) BeanUtil.getProperty(action, bound);
                }
                ////得到行总数 end
                turnPageButton.setRootDirectory(action.getEnv(ActionSupport.Key_RealPath));
                turnPageButton.setCurrentPath(action.getTemplatePath());
                turnPageButton.setFileName(turnFile);
                turnPageButton.setBound(StringUtil.toInt(bound, 3));
                BeanUtil.setSimpleProperty(action, method.getName(), turnPageButton.getTurnPage());
            }
        }
    }

    //------------------------------------------------------------------------------------------------------------------

    /**
     * 拷贝设置请求参数   拷贝代码
     * 注入action,这里需要
     * 注意：
     * 如果action为单例模式，第一次放入变量后，
     * 第二次还在，如果需要改变，那么必须明确的再次传入参数
     *
     * @param action action
     * @throws Exception 异常
     */
    public static void copyRequestProperty(Action action) throws Exception {
        if (action == null) return;
        if (action.getRequest() == null || RequestUtil.isRocRequest(action.getRequest())) return;
        HttpServletRequest request = action.getRequest();
        if (request instanceof MultipartSupport) {
            copyRequestProperty((MultipartSupport) action);
            return;
        }
        String[] requestNames = RequestUtil.getParameterNames(request);
        Method[] methods = ClassUtil.getDeclaredSetMethods(action.getClass());
        for (Method method : methods) {
            String propertyName = method.getName();
            if (StringUtil.isNULL(propertyName) || propertyName.startsWith(ClassUtil.methodName_get) || propertyName.startsWith(ClassUtil.methodName_is) || ArrayUtil.inArray(actionSafeMethod, propertyName, true))
                continue;
            if (propertyName.startsWith(ClassUtil.methodName_set) && propertyName.length() > 3) {
                propertyName = StringUtil.uncapitalize(propertyName.substring(3, propertyName.length()));
            }
            if (!ArrayUtil.inArray(requestNames, propertyName, true)) continue;

            Type[] types = method.getGenericParameterTypes();
            if (types.length < 1) continue;
            Type aType = types[0];
            Object propertyValue = null;
            if (ClassUtil.isArrayType(aType)) {
                if (aType.equals(int[].class)) {
                    propertyValue = action.getIntArray(propertyName);
                } else if (aType.equals(Integer[].class)) {
                    propertyValue = action.getIntegerArray(propertyName);
                } else if (aType.equals(long[].class)) {
                    propertyValue = action.getLongArray(propertyName);
                } else if (aType.equals(Long[].class)) {
                    propertyValue = action.getLongArray(propertyName);
                } else if (aType.equals(float[].class)) {
                    propertyValue = action.getFloatArray(propertyName);
                } else if (aType.equals(Float[].class)) {
                    propertyValue = action.getFloatObjectArray(propertyName);
                } else if (aType.equals(double[].class)) {
                    propertyValue = action.getDoubleArray(propertyName);
                } else if (aType.equals(Double[].class)) {
                    propertyValue = action.getDoubleObjectArray(propertyName);
                } else {
                    propertyValue = action.getArray(propertyName, false);
                }
            } else {
                if (aType.equals(Boolean.class) || aType.equals(boolean.class)) {
                    propertyValue = action.getBoolean(propertyName);
                } else if (aType.equals(int.class) || aType.equals(Integer.class)) {
                    propertyValue = action.getInt(propertyName);
                } else if (aType.equals(long.class) || aType.equals(Long.class)) {
                    propertyValue = action.getLong(propertyName);
                } else if (aType.equals(float.class) || aType.equals(Float.class)) {
                    propertyValue = action.getFloat(propertyName, 0);
                } else if (aType.equals(double.class) || aType.equals(Double.class)) {
                    propertyValue = action.getDouble(propertyName, 0);
                } else if (aType.equals(Date.class)) {
                    propertyValue = action.getDate(propertyName);
                } else if (aType.equals(java.sql.Date.class)) {
                    propertyValue = new java.sql.Date(action.getDate(propertyName).getTime());
                } else if (aType.equals(Timestamp.class)) {
                    propertyValue = new java.sql.Timestamp(action.getDate(propertyName).getTime());
                } else {
                    propertyValue = action.getString(propertyName);
                }
            }


            propertyValue = getSafeFilterValue(method, propertyValue);
            BeanUtil.setSimpleProperty(action, method.getName(), propertyValue);
        }
    }

    /**
     * 拷贝设置请求参数
     *
     * @param action action bean
     * @throws Exception 异常
     */
    @SuppressWarnings("unchecked")
    private static void copyRequestProperty(MultipartSupport action) throws Exception {
        MultipartRequest multipartRequest = action.getMultipartRequest();
        String[] requestNames = action.getParameterNames();
        Method[] methods = ClassUtil.getDeclaredSetMethods(action.getClass());
        for (Method method : methods) {
            String propertyName = method.getName();
            if (StringUtil.isNULL(propertyName) || propertyName.startsWith(ClassUtil.methodName_get) || propertyName.startsWith(ClassUtil.methodName_is)) {
                continue;
            }
            if (propertyName.startsWith(ClassUtil.methodName_set) && propertyName.length() > 3) {
                propertyName = StringUtil.uncapitalize(propertyName.substring(3));
            }
            if (!ArrayUtil.inArray(requestNames, propertyName, true)) {
                continue;
            }
            Object propertyValue;
            Type[] types = method.getGenericParameterTypes();
            if (types.length < 1) continue;

            Type aType = types[0];
            if (ClassUtil.isArrayType(aType)) {
                if (aType.equals(int[].class)) {
                    propertyValue = ArrayUtil.toIntArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(Integer[].class)) {
                    propertyValue = ArrayUtil.toIntegerArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(long[].class)) {
                    propertyValue = ArrayUtil.toLongArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(Long[].class)) {
                    propertyValue = ArrayUtil.toLongObjectArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(float[].class)) {
                    propertyValue = ArrayUtil.toFloatArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(Float[].class)) {
                    propertyValue = ArrayUtil.toFloatObjectArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(double[].class)) {
                    propertyValue = ArrayUtil.toDoubleArray(multipartRequest.getParameterValues(propertyName));
                } else if (aType.equals(Double[].class)) {
                    propertyValue = ArrayUtil.toDoubleObjectArray(multipartRequest.getParameterValues(propertyName));
                } else {
                    propertyValue = multipartRequest.getParameter(propertyName);
                }
            } else {
                if (aType == Boolean.class) {
                    propertyValue = Boolean.valueOf(StringUtil.toBoolean(multipartRequest.getParameter(propertyName)));
                } else if (aType == boolean.class) {
                    propertyValue = StringUtil.toBoolean(multipartRequest.getParameter(propertyName));
                } else if (aType == int.class) {
                    propertyValue = StringUtil.toInt(multipartRequest.getParameter(propertyName));
                } else if (aType == Integer.class) {
                    propertyValue = Integer.valueOf(StringUtil.toInt(multipartRequest.getParameter(propertyName)));
                } else if (aType == long.class) {
                    propertyValue = StringUtil.toLong(multipartRequest.getParameter(propertyName));
                } else if (aType == Long.class) {
                    propertyValue = Long.valueOf(StringUtil.toLong(multipartRequest.getParameter(propertyName)));
                } else if (aType == float.class) {
                    propertyValue = StringUtil.toFloat(multipartRequest.getParameter(propertyName));
                } else if (aType == Float.class) {
                    propertyValue = Float.valueOf(StringUtil.toFloat(multipartRequest.getParameter(propertyName)));
                } else if (aType == double.class) {
                    propertyValue = StringUtil.toDouble(multipartRequest.getParameter(propertyName));
                } else if (aType == Double.class) {
                    propertyValue = Double.valueOf(StringUtil.toDouble(multipartRequest.getParameter(propertyName)));
                } else if (aType == Date.class) {
                    propertyValue = StringUtil.toDate(multipartRequest.getParameter(propertyName));
                } else if (aType == java.sql.Date.class) {
                    propertyValue = new java.sql.Date(StringUtil.toDate(multipartRequest.getParameter(propertyName)).getTime());
                } else if (aType == Timestamp.class) {
                    propertyValue = new java.sql.Timestamp(StringUtil.toDate(multipartRequest.getParameter(propertyName)).getTime());
                } else {
                    propertyValue = multipartRequest.getParameter(propertyName);
                }
            }

            propertyValue = getSafeFilterValue(method, propertyValue);
            BeanUtil.setSimpleProperty(action, method.getName(), propertyValue);
        }
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * Safety 标签处理
     *
     * @param method
     * @param propertyValue
     * @return
     */
    public static Object getSafeFilterValue(Method method, Object propertyValue) {
        Safety safety = method.getAnnotation(Safety.class);
        if (safety == null) return propertyValue;
        if (propertyValue.getClass().isAssignableFrom(String.class)) {
            boolean isSafe = isSafe((String) propertyValue, safety.length(), safety.level());
            if (!isSafe) {
                if (safety.empty())
                    propertyValue = StringUtil.empty;
                else propertyValue = getSafeFilter((String) propertyValue, safety.length(), safety.level());
            }
        }

        //数组
        if (propertyValue.getClass().isArray()) {
            Object[] tempArray = (Object[]) propertyValue;
            for (int i = 0; i < tempArray.length; i++) {
                if (tempArray[i].getClass().isAssignableFrom(String.class)) {
                    boolean isSafe = isSafe((String) tempArray[i], safety.length(), safety.level());
                    if (!isSafe && safety.empty()) tempArray[i] = StringUtil.empty;
                    if (!isSafe && !safety.empty())
                        tempArray[i] = getSafeFilter((String) tempArray[i], safety.length(), safety.level());
                }
            }
            propertyValue = tempArray;
        }

        if (ClassUtil.isNumberType(method.getGenericParameterTypes()[0])) {
            long value = ObjectUtil.toLong(propertyValue);
            if (value > safety.max()) propertyValue = safety.max();
            if (value < safety.min()) propertyValue = safety.min();
        }
        return propertyValue;
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * @param action        action 对象
     * @param executeMethod 执行方法
     * @return 得到真实执行的方法，但要注意，这个方法在不满足条件的情况下不会执行
     * @throws Exception 异常
     */
    public static String getInvokeMethod(Action action, String executeMethod) throws Exception {
        if (StringUtil.isNULL(executeMethod) || executeMethod.equalsIgnoreCase("true") || !isSafe(executeMethod, 200, 1))
            return defaultExecute;
        if (executeMethod.startsWith(AT)) {
            //如果使用@ 标记,就动态得到参数的方法
            if (executeMethod.equals(AT)) {
                //RESTful 风格 例如:
                executeMethod = action.getEnv(ActionSupport.Key_ActionName);
            } else {
                executeMethod = action.getString(executeMethod.substring(1));
            }
        }
        return executeMethod;
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * 这里的主要功能是安全过滤，并且放入参数变量
     *
     * @param action   action对象
     * @param valueMap ROC请求参数
     * @throws Exception 异常
     */
    static void putJsonProperty(Action action, Map<String, Object> valueMap) throws Exception {
        if (action == null) return;
        Method[] methods = ClassUtil.getDeclaredSetMethods(action.getClass());
        for (Method method : methods) {
            String propertyName = method.getName();
            if (StringUtil.isNULL(propertyName) || propertyName.startsWith(ClassUtil.methodName_get) || propertyName.startsWith(ClassUtil.methodName_is) || ArrayUtil.inArray(actionSafeMethod, propertyName, true))
                continue;
            if (propertyName.startsWith(ClassUtil.methodName_set) && propertyName.length() > 3) {
                propertyName = StringUtil.uncapitalize(propertyName.substring(3, propertyName.length()));
            }
            if (!valueMap.containsKey(propertyName)) continue;
            Object propertyValue = valueMap.get(propertyName);
            Safety safety = method.getAnnotation(Safety.class);
            Type[] types = method.getGenericParameterTypes();
            if (safety != null) {
                if (types[0].equals(String[].class)) {
                    if (propertyValue instanceof String[]) {
                        String[] tempArray = (String[]) propertyValue;
                        for (int i = 0; i < tempArray.length; i++) {
                            boolean isSafe = isSafe(tempArray[i], safety.length(), safety.level());
                            if (!isSafe) {
                                if (safety.empty()) tempArray[i] = StringUtil.empty;
                                else tempArray[i] = getSafeFilter(tempArray[i], safety.length(), safety.level());
                            }
                        }
                        propertyValue = tempArray;
                    }
                    valueMap.put(propertyName, propertyValue);
                }
                if (types[0].equals(String.class)) {
                    boolean isSafe = isSafe(ObjectUtil.toString(propertyValue), safety.length(), safety.level());
                    if (!isSafe) {
                        if (safety.empty()) propertyValue = StringUtil.empty;
                        else
                            propertyValue = getSafeFilter(ObjectUtil.toString(propertyValue), safety.length(), safety.level());
                    }
                    valueMap.put(propertyName, propertyValue);
                }
                if (ClassUtil.isNumberType(types[0])) {
                    int value = ObjectUtil.toInt(propertyValue);
                    if (value > safety.max()) propertyValue = safety.max();
                    if (value < safety.min()) propertyValue = safety.min();
                    valueMap.put(propertyName, propertyValue);
                }
            }

            BeanUtil.setSimpleProperty(action, method.getName(), propertyValue);
        }
    }


    //------------------------------------------------------------------------------------------------------------------

    /**
     * 步骤: 1:先放入请求参数,2:执行请求方法;3:如果有多个返回，继续执行多个返回,5：最后执行defaultExecute
     *
     * @param actionProxy action对象
     * @throws Exception 异常
     */
    public static void invokeJson(ActionProxy actionProxy) throws Exception {
        //放入请求参数 begin
        Map<String, Object> actionParams = new HashMap<String, Object>();
        JSONObject callJson = actionProxy.getCallJson();
        JSONArray resultJson = callJson.getJSONArray(Environment.rocResult);
        ActionSupport action = actionProxy.getAction();
        action.setActionResult(ActionSupport.ROC);
        boolean rocSuperClass = callJson.getBoolean(Environment.rocSuperClass);
        //参数表示 set全局action参数
        JSONObject paramsJson = callJson.getJSONObject(Environment.rocParams);
        if (paramsJson != null) {
            for (Object key : paramsJson.keySet()) {
                Object objParam = paramsJson.get(key);
                if (objParam instanceof JSONArray) {
                    objParam = ((JSONArray) objParam).toArray();
                }
                actionParams.put((String) key, objParam);
            }
            putJsonProperty(action, actionParams);
        }
        //放入请求参数 end

        //ROC call Json 根据指定调用返回

        Method method = ClassUtil.getDeclaredMethod(action.getClass(), actionProxy.getMethod());
        if (method == null) {
            JSONObject errorJson = TXWebUtil.createRocErrorInfo(callJson.getString(Environment.rocId), ErrorRocCode.method_not_found, "method not found.找不到方法.");
            log.debug(errorJson.toString(4));
            action.setResult(errorJson.toString(4));
            return;
        }

        String exeMethod =  actionProxy.getMethod();
        boolean isVoid = false;
        Object methodResult = null;
        if (!TXWebUtil.defaultExecute.equals(exeMethod)) {
            JSONObject methodJson = callJson.getJSONObject(Environment.rocMethod);
            //这里是主函数的参数
            JSONArray paramsArray = null;
            if (methodJson != null && methodJson.containsKey(Environment.rocParams))
                paramsArray = methodJson.getJSONArray(Environment.rocParams);
            //else  paramsArray = callJson.getJSONArray(Environment.rocParams);
            Object[] params = null;
            if (paramsArray != null) params = new Object[paramsArray.size()];
            //参数不正确,这里是方法参数
            if (params != null) {
                if (params.length == 0) params = null;
                else {
                    for (int i = 0; i < paramsArray.size(); i++) {
                        params[i] = paramsArray.get(i);
                        if (params[i] instanceof JSONArray) {
                            params[i] = ((JSONArray) params[i]).toArray();
                        }
                    }
                }
            }
            try {
                if (method.getGenericReturnType().equals(Void.TYPE)) {
                    //如果不用返回,直接执行
                    isVoid = true;
                    invokeExecute(action, method, exeMethod,jsonType);
                } else {
                    methodResult = BeanUtil.getProperty(action, exeMethod, params, false);
                }
                //执行完后已经执行 execute，确保和form方式一样
            } catch (Exception e) {
                //RPC 2.0 标准  返回
                JSONObject errorJson = TXWebUtil.createRocErrorInfo(callJson.getString(Environment.rocId), ErrorRocCode.method_not_found, "method invoke error.执行方法发生错误," + exeMethod);
                log.debug(errorJson.toString(4), e);
                action.setResult(errorJson.toString(4));
                return;
            }
        }

        //如果在action中已经添加了返回对象，那么这里将跳过，不在放入返回数据
        //判断是否已经有返回结果，如果无返回数据，这里检查配置里边是否有配置返回方法
        if (!action.containsKey(ActionSupport.Key_ActionResultObject)) {
            JSONObject resultValueJson = new JSONObject();
            if (resultJson != null) {
                //这里目的是放入 多个数据对象
                for (Object v : resultJson.toArray()) {
                    String methods = (String) v;
                    //比较，判断是否还有没有返回的对象,避免外部写重复的方法
                    if (TXWebUtil.defaultExecute.equals(methods) || methods.equals(exeMethod) || resultValueJson.containsKey(exeMethod))
                        continue;
                    Object value = BeanUtil.getProperty(action, methods);
                    if (value == null) {
                        resultValueJson.put(methods, JSONObject.NULL);
                    } else if (value instanceof JSONObject) {
                        resultValueJson.put(methods, (JSONObject) value);
                    } else if (ClassUtil.isStandardProperty(value.getClass())) {
                        resultValueJson.put(methods, value);
                    } else
                        resultValueJson.put(methods, new JSONObject(value, rocSuperClass));
                }
            }
            //放入执行的结果
            if (!isVoid)
            {
                if (methodResult == null) {
                    resultValueJson.put(exeMethod, new JSONObject());
                } else if (ClassUtil.isStandardProperty(methodResult.getClass())|| BeanUtil.isArraySet(methodResult)) {
                    resultValueJson.put(exeMethod, methodResult);
                } else
                    resultValueJson.put(exeMethod, new JSONObject(methodResult, true));
            }
            //没有返回对象，就不添加了，后被统一返回信息
            if (!resultValueJson.isEmpty()) action.setResult(resultValueJson);
        }
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * 运行execute 必须会运行，如果不运行 在Operate 中设置条件
     *
     * @param action        action bean 已经支持上传action
     * @param executeMethod 调用的方法
     * @return action运行后的返回
     * @throws Exception 错误
     */
    public static String invokeExecute(Action action, String executeMethod, String infoType) throws Exception {
        //安全检查begin

        if (action == null) {
            log.error("invoke execute action is Null ,action 不能为空,请检查配置" + HtmlUtil.escapeHTML(executeMethod));
            throw new Exception("invoke execute action is Null ,action 不能为空,请检查配置" + HtmlUtil.escapeHTML(executeMethod));
        }
        Method exeMethod = null;
        executeMethod = getInvokeMethod(action, executeMethod);
        if (isSafe(executeMethod, 50, 1) && ClassUtil.isDeclaredMethod(action.getClass(), executeMethod)) {
            exeMethod = ClassUtil.getDeclaredMethod(action.getClass(), executeMethod);
        }
        //Reset 方式
        if (exeMethod == null && !TXWeb.httpPOST.equalsIgnoreCase(action.getRequest().getMethod())) {
            return action.getActionResult();
        }
        if (exeMethod == null) {
            if (debug) {
                JSONObject errorInfo = createRocErrorInfo(action.getEnv(ActionSupport.Key_ActionName), ErrorRocCode.invalidParameters, action.getClass().getName() + " invoke execute action method not find,没有找到调用方法:" + HtmlUtil.escapeHTML(executeMethod));
                print(errorInfo.toString(4), jsonType, action.getResponse(), HttpStatusType.HTTP_status_403);
                log.error(action.getClass().getName() + " invoke execute action method not find,没有找到调用方法:" + HtmlUtil.escapeHTML(executeMethod));
            } else {
                JSONObject errorInfo = createRocErrorInfo(action.getEnv(ActionSupport.Key_ActionName), ErrorRocCode.invalidParameters, "非法调用:" + HtmlUtil.escapeHTML(executeMethod));
                print(errorInfo.toString(4), jsonType, action.getResponse(), HttpStatusType.HTTP_status_403);
            }
            return ActionSupport.KEY_RETURN;
        }
        ////////////////execute begin
        if (defaultExecute.equals(exeMethod.getName())) {
            return action.execute();
        } else {
            invokeExecute(action, exeMethod, executeMethod,infoType);
        }

        /*
          //跳转 Redirect 判断 begin
        //保存到环境变量里边
        Redirect redirect = exeMethod.getAnnotation(Redirect.class);
        if (redirect != null) {
            action.put(ActionSupport.KEY_RedirectUrl, redirect.location());
            action.setActionResult(ActionSupport.REDIRECT);
        }
        //跳转 Redirect 判断 end
         */

        return action.getActionResult();
    }

    public static void invokeExecute(Action action, Method exeMethod,String executeMethod,String infoType)
    {
        Operate operate = exeMethod.getAnnotation(Operate.class);
        //注意，档位GET的时候 submit 为 false
        if (operate != null && TXWeb.httpPOST.equalsIgnoreCase(action.getRequest().getMethod()) == operate.submit()) {
            try {

                //验证 begin
                Validate validate = exeMethod.getAnnotation(Validate.class);
                if (validate != null && !StringUtil.isNULL(validate.formId()) && !StringUtil.isNULL(validate.name()) && !StringUtil.isNULL(action.getString(executeMethod))) {
                    String namespace = validate.namespace();
                    if (StringUtil.isNULL(validate.namespace()) || Sioc.global.equalsIgnoreCase(validate.namespace()))
                        namespace = action.getEnv(ActionSupport.Key_Namespace);
                    Object obj = beanFactory.getBean(validate.name(), namespace);
                    Validator dataTypeValidator = null;
                    if (obj instanceof Validator) {
                        Validator validator = (Validator) obj;
                        ValidatorAction validatorAction = new ValidatorAction();
                        validatorAction.setConfigFile(validator.getConfigFile());
                        validatorAction.setType(validate.infoType());
                        validatorAction.setRequest(action.getRequest());
                        validatorAction.setResponse(action.getResponse());
                        dataTypeValidator = validatorAction.getProcessor();
                    }
                    if (obj instanceof ValidatorAction) {
                        ValidatorAction vv = (ValidatorAction) obj;
                        dataTypeValidator = vv.getProcessor();
                    }
                    if (dataTypeValidator == null) {
                        print("validate config no find :bean name " + HtmlUtil.escapeHTML(validate.name()) + "     namespace=" + HtmlUtil.escapeHTML(namespace), infoType, action.getResponse(), HttpStatusType.HTTP_status_403);
                        return;
                    }
                    dataTypeValidator.setCheckObject(action.getRequest());
                    String formId = validate.formId();
                    if (validate.formId().startsWith(AT)) {
                        formId = RequestUtil.getString(action.getRequest(), formId.substring(1, formId.length()), true);
                    }
                    if (StringUtil.isNULL(formId) || ActionSupport.NONE.equals(formId)) {
                        print("data type validator " + action.getClass().getName() + " not find form id", infoType, action.getResponse(), HttpStatusType.HTTP_status_403);
                        return;
                    } else {
                        dataTypeValidator.setFormId(formId);
                        action.addFieldInfo(dataTypeValidator.getInformation(validate.infoType()));
                    }
                }
                //验证 end
                if (operate.hasFieldInfo() == action.hasFieldInfo()) {
                    exeMethod.invoke(action);
                    action.put(ActionSupport.Key_CallMethodName, executeMethod);
                }
            } catch (Exception e) {
                if (debug) {
                    log.error(action.getClass() + ",method:" + HtmlUtil.escapeHTML(executeMethod), e);
                    print(action.getClass() + ",method:" + HtmlUtil.escapeHTML(executeMethod) + " " + StringUtil.toBrLine(e.getLocalizedMessage()), infoType, action.getResponse(), HttpStatusType.HTTP_status_403);
                } else
                    errorPrint(action.getEnv(ActionSupport.Key_ActionName) + ",method:" + HtmlUtil.escapeHTML(executeMethod), action.getResponse(), 500);

            }
        }
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * 得到namespace
     *
     * @param servletPath 传入 request.servletPath
     * @return namespace 命名空间
     */
    public static String getNamespace(String servletPath) {
        String namespace = URLUtil.getURLPath(servletPath);
        if (namespace == null) return StringUtil.empty;
        if (namespace.endsWith("/")) {
            namespace = namespace.substring(0, namespace.length() - 1);
        }
        if (namespace.startsWith("/")) {
            namespace = namespace.substring(1, namespace.length());
        }
        if ("/".equals(namespace)) return StringUtil.empty;
        return namespace;
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * @param servletPath 得到方法
     * @return 得到更目录
     */
    public static String getRootNamespace(String servletPath) {
        if (servletPath == null) return StringUtil.empty;
        if (!servletPath.contains("/")) return servletPath;
        if (servletPath.startsWith("http"))
            servletPath = StringUtil.substringAfter(servletPath, URLUtil.getHostURL(servletPath));
        String namespace = URLUtil.getURLPath(servletPath);
        if (namespace == null) return StringUtil.empty;
        if (namespace.startsWith("/")) namespace = namespace.substring(1, namespace.length());
        if (namespace.contains("/")) return StringUtil.substringBefore(namespace, "/");
        return namespace;
    }
    //------------------------------------------------------------------------------------------------------------------

    /**
     * @param namespace   命名空间
     * @param actionName  文件名
     * @param classMethod 执行动作
     * @return 得到唯一识别的动作方法ID
     */
    public static String getOperateMethodId(String namespace, String actionName, String classMethod) {
        return namespace + Role.roleNamespace + EncryptUtil.getBase64EncodeString(actionName, EncryptUtil.NO_WRAP) + Role.roleMethod + classMethod;
    }

    /**
     * 得到操作入口 actionName
     *
     * @param line
     * @return
     */
    public static String getOperateActionName(String line) {
        if (line == null) return StringUtil.empty;
        String actionName = StringUtil.substringBetween(line, Role.roleNamespace, Role.roleMethod);
        if (actionName == null) return StringUtil.empty;
        try {
            return StringUtil.trim(EncryptUtil.getBase64DecodeString(actionName));
        } catch (Exception e) {
            log.error("getOperateActionName error " + line, e);
            return StringUtil.empty;
        }

    }

    //------------------------------------------------------------------------------------------------------------------
    public static void print(String string, final String type, HttpServletResponse response) {
        print(string, type, response, 0);
    }

    /**
     * @param string   字符串
     * @param type     类型
     * @param response 应答
     */
    public static void print(String string, final String type, HttpServletResponse response, int status) {
        if (response.isCommitted()) {
            log.error("response 已经提交并且关闭,又输出信息:" + string);
            return;
        }
        String contentType = "text/html";
        if (jsonType.equalsIgnoreCase(type)) contentType = "application/json";
        if (javascriptType.equalsIgnoreCase(type))
            contentType = "text/javascript; charset=" + response.getCharacterEncoding();
        if (xmlType.equalsIgnoreCase(type)) contentType = "text/xml";

        response.setContentType(contentType + "; charset=" + response.getCharacterEncoding());
        if (status > 0) response.setStatus(status);
        PrintWriter out = null;
        try {
            out = response.getWriter();
            if (javascriptType.equalsIgnoreCase(type)) {
                out.print("document.write(" + StringUtil.toJavaScriptQuote(string) + ");");
            } else
                out.print(string);
            out.close();
        } catch (IOException e1) {
            log.error("response writer is close,not out error", e1);
        }
    }

    /**
     * 格式兼容
     *
     * @param json
     * @param type
     * @param response
     * @param status
     */
    public static void print(JSONObject json, final String type, HttpServletResponse response, int status) {
        if (jsonType.equalsIgnoreCase(type)) {
            print(json.toString(4), jsonType, response, status);
        } else if (xmlType.equalsIgnoreCase(type)) {
            try {
                print(XML.toString(json), xmlType, response, status);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } else {
            try {
                print(HtmlUtil.deleteHtml(XML.toString(json)), xmlType, response, status);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @return Map   创建默认环境
     */
    public static Map<String, Object> createEnvironment() {
        EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
        Map<String, Object> venParams = new HashMap<String, Object>();
        venParams.put(Environment.filterSuffix, envTemplate.getString(Environment.filterSuffix));
        venParams.put(Environment.templateSuffix, envTemplate.getString(Environment.templateSuffix));
        venParams.put(Environment.encode, Dispatcher.getEncode());
        venParams.put(Environment.remoteHostUrl, envTemplate.getString(Environment.remoteHostUrl, ""));
        venParams.put(Environment.scriptPath, envTemplate.getString(Environment.scriptPath, "/script"));
        venParams.put(Environment.sitePath, envTemplate.getString(Environment.sitePath, "/"));
        venParams.put(Environment.userLoginUrl, envTemplate.getString(Environment.userLoginUrl, "/user/index." + envTemplate.getString(Environment.filterSuffix)));
        venParams.put(Environment.logJspxDebug, envTemplate.getBoolean(Environment.logJspxDebug));
        venParams.put("date", new Date());
        return venParams;
    }


    public static void errorPrint(String info, HttpServletResponse response, int status) {

        if (response.isCommitted()) {
            log.error("response 已经提交并且关闭,又输出错误信息:" + info + ",检查执行代码，之前错误信息");
            return;
        }
        if (response.getStatus() != 200) return;
        EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
        TemplateConfigurable configurable = new TemplateConfigurable();
        configurable.addAutoIncludes(envTemplate.getString(Environment.autoIncludes));
        File f = new File(envTemplate.getString(Environment.templatePath), envTemplate.getString(Environment.errorInfoPageTemplate, "error.ftl"));
        AbstractSource fileSource = new FileSource(f, envTemplate.getString(Environment.templatePath), envTemplate.getString(Environment.encode, Environment.defaultEncode));
        configurable.setSearchPath(new String[]{envTemplate.getString(Environment.templatePath), Dispatcher.getRealPath()});
        ScriptMark scriptMark;
        try {
            scriptMark = new ScriptMarkEngine(ScriptmarkEnv.noCache, fileSource, configurable);
        } catch (Exception e) {
            log.error("error template page not found" + f.getAbsolutePath(), e);
            TXWebUtil.print("error template page not found,错误信息显示模版没有配置", TXWebUtil.htmlType, response);
            return;
        }

        scriptMark.setRootDirectory(Dispatcher.getRealPath());
        scriptMark.setCurrentPath(envTemplate.getString(Environment.templatePath));
        //输出模板数据
        Map<String, Object> valueMap = createEnvironment();
        valueMap.put(Environment.message, info);
        valueMap.put(ActionSupport.Key_Response, RequestUtil.getResponseMap(response));
        PrintWriter out = null;
        try {
            out = response.getWriter();
            response.setStatus(status);
            scriptMark.process(out, valueMap);
            if (out != null) out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建登录验证码
     *
     * @param uid
     * @param loginId
     * @param publicKey
     * @param privateKey
     * @param password
     * @param passwordEncoded
     * @param timeMillis
     * @return
     */
    public static String getLoginHashVerify(String uid, String loginId, String publicKey, String privateKey, String password, int passwordEncoded, long timeMillis) {
        return EncryptUtil.getMd5("[" + uid + ":" + loginId + "]" + StringUtil.SEMICOLON + publicKey + privateKey + StringUtil.SEMICOLON + password + StringUtil.SEMICOLON + passwordEncoded + StringUtil.SEMICOLON + timeMillis);
    }

    /**
     * appId方式登录验证,得到 jsessionId
     *
     * @param appId      ConnectApp中的ID
     * @param publicKey  共密
     * @param privateKey 私密
     * @param timeMillis 时间
     * @return
     */
    public static String getAppHashVerify(long appId, String publicKey, String privateKey, long timeMillis) {
        return EncryptUtil.getMd5(appId + StringUtil.SEMICOLON + publicKey + privateKey + StringUtil.SEMICOLON + StringUtil.SEMICOLON + timeMillis);
    }

    /**
     * roc 错误信息格式固定输出
     *
     * @param rocId
     * @param errorCode
     * @param info
     * @return
     */
    public static JSONObject createRocErrorInfo(String rocId, int errorCode, String info) {
        JSONObject errorResultJson = new JSONObject();
        errorResultJson.put(Environment.rocProtocol, Environment.jspxNetRoc);
        errorResultJson.put(Environment.rocVersion, Environment.jspxNetRocVersion);
        errorResultJson.put(Environment.rocId, rocId);
        JSONObject errorJson = new JSONObject();
        errorResultJson.put(Environment.id_error, errorJson);
        errorJson.put(Environment.id_errorCode, errorCode);
        errorJson.put(Environment.id_message, info);
        //目的只是为了兼容
        errorResultJson.put(Environment.message, info);
        errorResultJson.put(Environment.SUCCESS, 0);
        return errorResultJson;
    }

    /**
     * 用户密码加密算法
     *
     * @param password
     * @return
     */
    public static String getPasswordHashEncode(String password) {
        ///////////////////判断是否有游客帐号，没有就创建一个
        return EncryptUtil.getHashEncode(password + EnvFactory.getHashAlgorithmKey(), EnvFactory.getHashAlgorithm());
        ///////////////////
    }

    public static String createPasswordSaveFormat(String password) {
        return "[" + EnvFactory.getHashAlgorithm() + "." + EnvFactory.getHashAlgorithmKey() + "]" + getPasswordHashEncode(password);
    }

}